#include <windows.h>
#include <commctrl.h>

#include "lib.h"
#include "bitmap.h"
#include "screen.h"

#include "gfxdialog.h"
#include "gfxobject.h"
#include "gfxutils.h"
using namespace GraphicUtils;

#define SELF	GraphicDialog
#define SUPER	Dialog


//----------------------------------------------------------------------------
// Public
//
GraphicDialog::GraphicDialog(HWND hParent, HINSTANCE hInstance)
	: SUPER(hParent, hInstance)
{
	m_bground		= (pCBitmap)0;
//	m_hDblBufDC		= (HDC)0;
//	m_hBmpDC		= createMemDC();
//	m_hMaskDC		= CreateCompatibleDC(m_hBmpDC);
//	m_hWasBmp		= (HBITMAP)0;
	m_result		= IDCANCEL;
}

GraphicDialog::~GraphicDialog()
{
//	if (m_hWasBmp)
//	{
//		SelectObject(m_hBmpDC, m_hWasBmp);
//		SelectObject(m_hMaskDC, m_hWasBmp);
//	}
//
//	deleteDblBufDC();
//	DeleteDC(m_hBmpDC);
//	DeleteDC(m_hMaskDC);

	// Do not delete m_bground; that is the responsibility of the class who
	// loaded it.
}


//----------------------------------------------------------------------------
// Protected
//
BOOL
GraphicDialog::drawBackground(HWND hWnd)
{
	PAINTSTRUCT		ps;
	HDC				hdc;
	RECT			rc;

	// If there's no background image, then there's nothing to draw.  We
	// return FALSE to let Windows know we handled the WM_PAINT message despite
	// the missing graphic.
	if (!m_bground)
		return FALSE;

	hdc = BeginPaint(hWnd, &ps);
	if (hdc)
	{
		if (ps.fErase || IsRectEmpty(&ps.rcPaint))
		{
			GetClientRect(hWnd, &rc);
			blt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
				CBitmapHBmp(m_bground), 0, 0);
		}
		else
		{
			blt(hdc, ps.rcPaint.left, ps.rcPaint.top,
				ps.rcPaint.right - ps.rcPaint.left,
				ps.rcPaint.bottom - ps.rcPaint.top, CBitmapHBmp(m_bground),
				0, 0);
		}
	}

	EndPaint(hWnd, &ps);

	// Despite any errors we might have, we'll inform Windows that we handled
	// the WM_PAINT message.
	return FALSE;
}


void
GraphicDialog::end(int32 Id)
{
	EndDialog(m_hDialog, Id);
}


bool8
GraphicDialog::initialize()
{
	return true;
}


BOOL
GraphicDialog::dialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
		case WM_INITDIALOG:
			initialize();
			return TRUE;

		case WM_CTLCOLORBTN:
		case WM_CTLCOLORDLG:
		case WM_CTLCOLOREDIT:
		case WM_CTLCOLORLISTBOX:
		case WM_CTLCOLORSCROLLBAR:
		case WM_CTLCOLORSTATIC:
		{
			GraphicObject *	gfxobject;
			
			gfxobject = (GraphicObject *)GetWindowLong((HWND)lParam, GWL_USERDATA);

			if (gfxobject)
			{
				return (BOOL)gfxobject->onControlColor((HDC)wParam);
			}

			SetBkMode((HDC)wParam, TRANSPARENT);
			return (BOOL)GetStockObject(NULL_BRUSH);
		}

		case WM_ERASEBKGND:
			return 1;

		case WM_PAINT:
			return drawBackground(hWnd);
			break;

		case WM_NOTIFY:
		{
			LPNMHDR	lpnmhdr = (LPNMHDR)lParam;

			switch (lpnmhdr->code)
			{
				case NM_CUSTOMDRAW:
				{
					GraphicObject *	gfxobject;
					LRESULT			lResult;
					
					gfxobject = (GraphicObject *)GetWindowLong(lpnmhdr->hwndFrom, GWL_USERDATA);
					if (gfxobject &&
						gfxobject->paint((LPNMCUSTOMDRAW)lParam, &lResult))
					{
						SetWindowLong(hWnd, DWL_MSGRESULT, lResult);
						return TRUE;
					}

					break;
				}

				default:
					break;
			}
			break;
		}

		case WM_DRAWITEM:
		{
			LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
			GraphicObject *  gfxobject;

			gfxobject = (GraphicObject *)GetWindowLong(lpdis->hwndItem, GWL_USERDATA);
			if (gfxobject && gfxobject->paint(lpdis))
				return TRUE;

			break;
		}

		case WM_COMMAND:
		{
			if (HIWORD(wParam) == BN_CLICKED)
			{
				switch (LOWORD(wParam))
				{
					case IDOK:
					case IDCANCEL:
						end(LOWORD(wParam));
						return TRUE;

					default:
					{
						GraphicButton * gfxbutton;
						bool8 rv = FALSE;

						// Allow the component to handle the message.
						gfxbutton = (GraphicButton *)GetWindowLong((HWND)lParam, GWL_USERDATA);
						if (gfxbutton)
							rv = gfxbutton->bn_clicked();

						// Notify the subclass (this is to fix message ordering).
						bn_clicked((HWND)lParam, (uint32)LOWORD(wParam));

						// If the component handled it, we're done.
						if (rv)
							return TRUE;

						break;
					}
				}
			}
			else
			{
				GraphicObject *	gfxobject;
				
				gfxobject = (GraphicObject *)GetWindowLong((HWND)lParam, GWL_USERDATA);

				if (gfxobject)
				{
					gfxobject->onCommand(HIWORD(wParam));
				}
			}
		}

		default:
			break;
	} 

	return SUPER::dialogProc(hWnd, uMsg, wParam, lParam);
}


void
GraphicDialog::bn_clicked(HWND hWnd, uint32 ctrlID)
{
}


#if 0

bool8
GraphicDialog::initialize()
{
	return true;
}

void
GraphicDialog::forceSize(HWND hWnd)
{
	RECT r[2];

	//
	// get rid of dialog units...
	// we control the horizontal; we control the vertical...
	//
	// left/top are original dialog units; right/bottom are what *we* want
	//
	SetRect(r, 0, 0, 4, 8);
	MapDialogRect(hWnd, r);

	r[0].left = r[0].right;
	r[0].top = r[0].bottom;
	r[0].right = 6;
	r[0].bottom = 13;
	GetWindowRect(hWnd, r + 1);
	
	EnumChildWindows(hWnd, (WNDENUMPROC)resizeChild, (LPARAM)r);
}

BOOL FAR PASCAL
GraphicDialog::resizeChild(HWND hChild, LPRECT rdlg)
{
	RECT rch;
	wchar_t classname[32];

	GetWindowRect(hChild, &rch);
	GetClassName(hChild, classname, 32);
	if (0 == wcsicmp(classname, TEXT("COMBOBOX")))
	{
		DWORD style = GetWindowLong(hChild, GWL_STYLE);

		if ((style & CBS_DROPDOWN) || (style & CBS_DROPDOWNLIST))
			SendMessage(hChild, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rch);
	}

	OffsetRect(&rch, -rdlg[1].left, -rdlg[1].top);

	rch.left = MulDiv(rch.left, rdlg[0].right, rdlg[0].left);
	rch.right = MulDiv(rch.right, rdlg[0].right, rdlg[0].left);
	rch.top = MulDiv(rch.top, rdlg[0].bottom, rdlg[0].top);
	rch.bottom = MulDiv(rch.bottom, rdlg[0].bottom, rdlg[0].top);

	MoveWindow(hChild, rch.left, rch.top,
		rch.right - rch.left + 1, rch.bottom - rch.top + 1, FALSE);

	return TRUE;
}

void
GraphicDialog::center()
{
	HWND hAppTop = m_hParent;
	RECT rcTop, rcMe;

	GetClientRect(hAppTop, &rcTop);
	ClientToScreen(hAppTop, (LPPOINT)&rcTop);

	if (CBitmapHBmp(m_bground))
		SetRect(&rcMe, 0, 0, CBitmapWidth(m_bground), CBitmapHeight(m_bground));
	else
		GetClientRect(m_hDialog, &rcMe);

	SetWindowPos(m_hDialog, HWND_TOP,
		rcTop.left + ((rcTop.right - rcMe.right) >> 1),
		rcTop.top + ((rcTop.bottom - rcMe.bottom) >> 1),
		rcMe.right, rcMe.bottom, 0);
}

void
GraphicDialog::show()
{
	center();

	ShowWindow(m_hDialog, SW_SHOW);
	UpdateWindow(m_hParent);
	UpdateWindow(m_hDialog);
}

void
GraphicDialog::setFonts()
{
}

void
GraphicDialog::restoreFonts()
{
}

HWND
GraphicDialog::validData(String& /*error msg*/)
{
	return (HWND)0;		// all ok by default
}

void
GraphicDialog::UIinputAllowed(bool8 /*Allowed*/)
{
}

HDC
GraphicDialog::createMemDC()
{
	HDC hdc, hresult;

	hdc = GetDC(m_hParent);
	hresult = CreateCompatibleDC(hdc);
	ReleaseDC(m_hParent, hdc);

	return hresult;
}

void
GraphicDialog::createDblBufDC()
{
	if (m_bground && CBitmapHBmp(m_bground))
	{
		POINT sz;

		sz.x = sz.y = 0;
		EnumChildWindows(m_hDialog, (WNDENUMPROC)maxChildDimensions,
			(LPARAM)&sz);

		m_hDblBufDC = CreateCompatibleDC(m_hBmpDC);

		m_hWasBmp = (HBITMAP)SelectObject(m_hBmpDC, CBitmapHBmp(m_bground));
		SelectObject(m_hDblBufDC, CreateCompatibleBitmap(m_hBmpDC, sz.x, sz.y));
		SelectObject(m_hBmpDC, m_hWasBmp);
	}
}

BOOL FAR PASCAL
GraphicDialog::maxChildDimensions(HWND hChild, void* pSZ)
{
	RECT r;
	LPPOINT psz = (LPPOINT)pSZ;

	GetClientRect(hChild, &r);

	if (r.right > psz->x)
		psz->x = r.right;

	if (r.bottom > psz->y)
		psz->y = r.bottom;

	return TRUE;
}

void
GraphicDialog::deleteDblBufDC()
{
	if (m_hDblBufDC)
	{
		HBITMAP hdblbuf = (HBITMAP)SelectObject(m_hDblBufDC, m_hWasBmp);

		if (hdblbuf)
			DeleteObject(hdblbuf);

		DeleteDC(m_hDblBufDC);
	}
}

HBITMAP
GraphicDialog::createMask(pCBitmap bmp)
{
	return CBitmapMonoMask(bmp);
}

pCBitmap
GraphicDialog::createTransMask(pCBitmap bmp)
{
	return CBitmapTransMask(bmp);
}

void
GraphicDialog::blt(HDC hdest, int32 dx, int32 dy, int32 dw, int32 dh,
	HBITMAP hsrc, int32 sx, int32 sy)
{
	HBITMAP oldbmp;

	oldbmp = (HBITMAP)SelectObject(m_hBmpDC, hsrc);
	BitBlt(hdest, dx, dy, dw, dh, m_hBmpDC, sx, sy, SRCCOPY);
	SelectObject(m_hBmpDC, oldbmp);
}

void
GraphicDialog::blt(HDC hdest, int32 dx, int32 dy, int32 dw, int32 dh,
	HBITMAP hsrc, HBITMAP hmask, HBITMAP htmask, int32 sx, int32 sy)
{
	HBITMAP oldbmp, oldmask;

	oldbmp = (HBITMAP)SelectObject(m_hBmpDC, hsrc);
	oldmask = (HBITMAP)SelectObject(m_hMaskDC, hmask);

	BitBlt(hdest, dx, dy, dw, dh, m_hMaskDC, sx, sy, SRCAND);
	SelectObject(m_hMaskDC, htmask);
	BitBlt(hdest, dx, dy, dw, dh, m_hMaskDC, sx, sy, SRCINVERT);
	BitBlt(hdest, dx, dy, dw, dh, m_hBmpDC, sx, sy, SRCINVERT);
	SelectObject(m_hMaskDC, hmask);

	SelectObject(m_hBmpDC, oldbmp);
	SelectObject(m_hMaskDC, oldmask);
}

BOOL
GraphicDialog::drawBackground(HDC hdest)
{
	HBITMAP		mbmp;
	pCBitmap	tbmp;

	if (m_bground)
	{
		mbmp = createMask(m_bground);
		tbmp = createTransMask(m_bground);
		if (mbmp && tbmp)
		{
			blt(hdest, 0, 0, CBitmapWidth(m_bground), CBitmapHeight(m_bground),
				CBitmapHBmp(m_bground), mbmp, CBitmapHBmp(tbmp),
				0, 0);
		}
		else
		{
			blt(hdest, 0, 0, CBitmapWidth(m_bground), CBitmapHeight(m_bground),
				CBitmapHBmp(m_bground), 0, 0);
		}

		DeleteObject(mbmp);
		deleteCBitmap(tbmp);

		return TRUE;
	}
	return FALSE;
}

void
GraphicDialog::drawButton(LPARAM lParam, pCBitmap bmp, HBITMAP mask)
{
#if 0
	LPDRAWITEMSTRUCT lpd = (LPDRAWITEMSTRUCT)lParam;
	int32 dx, dy, txtlen;
	wchar_t txt[80];
	RECT r;
	pCBitmap mask2;

	HDC hdest = (hDblBufDC ? hDblBufDC : lpd->hDC);
	
	if (lpd->itemState & ODS_SELECTED)
		dx = dy = 2;
	else
		dx = dy = 0;

	txtlen = GetWindowText(lpd->hwndItem, txt, 80);

	SendMessage(hDialog, WM_CTLCOLORBTN,
		(WPARAM)hdest, (LPARAM)lpd->hwndItem);

	r = lpd->rcItem;
	MapWindowPoints(lpd->hwndItem, hDialog, (LPPOINT)&r, 2);

	blt(hdest, 0, 0, r.right - r.left, r.bottom - r.top,
		CBitmapHBmp(bground), r.left, r.top);

	if (mask)
	{
		mask2 = CBitmapTransMask(bmp);

		blt(hdest, dx, dy, CBitmapWidth(bmp), CBitmapHeight(bmp),
			CBitmapHBmp(bmp), mask, CBitmapHBmp(mask2), 0, 0);
		
		deleteCBitmap(mask2);
		mask2 = 0;
	}
	else
		blt(hdest, dx, dy, CBitmapWidth(bmp), CBitmapHeight(bmp),
			CBitmapHBmp(bmp), 0, 0);

	if (txtlen)
	{
		RECT rect;

		SetRect(&rect, 0, 0, CBitmapWidth(bmp), CBitmapHeight(bmp));
		OffsetRect(&rect,
			dx + ((CBitmapWidth(bmp) - rect.right) >> 1),
			dy + ((CBitmapHeight(bmp) - rect.bottom) >> 1));

		TextBlock txBlock;
		
		txBlock.backgroundColor(lobby->getMenuManager()->getBColorDialogButtons());

		MenuManager* menumgr = lobby->getMenuManager();
		int32 fontSize = menumgr->getLoginButtonNormalFontSize();
		if (IsWindowEnabled(lpd->hwndItem))
		{
			if (lpd->itemState & ODS_SELECTED || lpd->itemState & ODS_FOCUS)
			{
				txBlock.font(Lobby::getFontHighlight());
				fontSize = menumgr->getLoginButtonHighLightFontSize();
			}
			else 
			{
				txBlock.font(Lobby::getFontNormal());
			}
		}
		else 
		{
			txBlock.font(Lobby::getFontDisabled());
		}
		
		txBlock.fontSize(fontSize);

		txBlock.blockWidth(CBitmapWidth(bmp));
		txBlock.blockHeight(CBitmapHeight(bmp));
		txBlock.horizontalPosition(TextBlock::HP_CENTER_GFX);
		txBlock.verticalPosition(TextBlock::VP_CENTER_TEXT);
		txBlock.text(txt);

		pCBitmap textBitmap = txBlock.bitmap();
		
		HBITMAP textmask = createMask(textBitmap);

		mask2 = createTransMask(textBitmap);
		
		blt(hdest, dx, dy, CBitmapWidth(textBitmap), CBitmapHeight(textBitmap),
			CBitmapHBmp(textBitmap), textmask, CBitmapHBmp(mask2), 0, 0);

		if (textmask)
			DeleteObject(textmask);
	
		deleteCBitmap(mask2);
		mask2 = 0;
	}	

	if (lpd->itemState & ODS_FOCUS)
	{
		//RECT r;
		//SetRect(&r, 0, 0, CBitmapWidth(bmp), CBitmapHeight(bmp));
		//FrameRect(hdest, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
	}

	if (hDblBufDC)
	{
		BitBlt(lpd->hDC, 0, 0, CBitmapWidth(bmp)+2, CBitmapHeight(bmp)+2,
			hdest, 0, 0, SRCCOPY);
	}
#endif
}

void
GraphicDialog::setText()
{
}
#endif



//
// vim: nowrap
//
